#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//1.按位取反 ~ : 将二进制位的0变成1, 1变成0
void test01()
{
    int number = 2; //2的二进制是010  (对于正数 源码 反码 补码都一样),负数使用补码存储
    printf("~number: %d\n", ~number);//010按位取反是101(发现是负数,那其是补码) 将101转换为源码110+1=111 所以是 -3
    //怎么判断正负,要看数值类型, number的类型是int 是有符号位的
}

//2.位与 &  :  上下两个位都位1,才是1,否则都是0
//    10011
//& 00010
//    00010
//一个数通过&上一个特殊的例如1000或者0010 就可以直到它的二进制位的某一位是1还是0
//另外位与可以将二进制的某一位置0
void test02()
{
    //发现一个数&1,结果是0就是偶数, 是1就是奇数
    int number = 352;
    if((number & 1) == 0){
        printf("%d是偶数\n", number);
    }else{
        printf("%d是奇数\n", number);
    }

    //一个数&0，其实就是清0操作,最终结果为0
    number = number & 0;
    printf("number:%d\n", number);
}

//3 位或 | :  上下两位只要一位是1,就为1
//可以将二进制位的某一位置1
void test03()
{
    int num1 = 5;
    int num2 = 3;

    printf("num1 | num2 = %d\n", num1 | num2);
}

//4 位异或 ^ : 上下两个相等是0. 不相等为1
//一个数异或两次另一个数,得到是本身： A ^ B ^ B = A
//异或可以将两个数交换
void test04()
{
    int num1 = 5;
    int num2 = 9;

#if 0
    int temp = num1;
    num1 = num2;
    num2 = temp;
#endif

    printf("num1:%d num2:%d\n", num1, num2);

    num1 = num1 ^ num2;
    num2 = num1 ^ num2; //num2 = num1
    num1 = num1 ^ num2; 

    printf("num1:%d num2:%d\n", num1, num2);
}

//5 左移 << : 就是将这个二进制向左移动,左边移出的舍去,右边空出来补0
//一个数左移几位就相当于这个数乘以2的几次方
void test05()
{
    int number = 20;
    printf("number = %d\n",  number <<1);
}

//5 右移 >> : 就是将这个二进制向右移动,丢弃移出左侧操作位, 右边对于unsigned类型,使用0填充左端空出的位,对于有符号类型,结果依赖于机器
//空出的位可能用0填充,或者使用符号(最左端)位的副本填充
//一个非负数向右移动几位,相当于这个数除以2的n次幂
void test06()
{
    int number = 20;
    printf("number = %d\n",  number <<= 2);
    printf("number = %d\n",  number  >>= 1);
}

int main(int argc, char const *argv[])
{
    test01();   
    test02();   
    test03();   
    test04();   
    test05();   
    test06();   
    return 0;
}
